package metodos;

import Compilador.Plantilla;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.JOptionPane;


public class TablaOneRule {

    String nombre; //El nombre del atributo.
    String nombreSalida; //Nombre del atributo de salida.
    ArrayList<ArrayList<String>> lista; //Aqui se guardan los datos que se reciben.
    ArrayList<ArrayList<Integer>> datos; //Aqui se guarda la cantidad de veces que se repite cada dato
    ArrayList<String> valores; //Aqui se guardan los posibles valores del atributo evaluado
    ArrayList<String> valoresClase; //Aqui se guardan los posibles valores de la "clase"
    ArrayList<String> reglas; //Aqui se guarda el resultado de cada valor de atributo
    int cantidadVerdadera; //Aqui se indica cuantos registros fueron existosos con la regla.
    float porcentaje; //Porcentaje de veracidad de esta regla
    ArrayList<ArrayList<String>> posiblesValores; //Contiene los posibles valores que tiene cada atributo.
    String[] titulos; //Contiene los titulos de todos los atributos.

    /**
     * Establece la vista minable con la cual se trabajará.
     *
     * @param lista
     */
    public void setLista(ArrayList<ArrayList<String>> lista) {
        this.lista = lista;
    }

    /**
     * Establece el nombre del atributo que se está trabajando en esta tabla.
     *
     * @param nombre
     */
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    /**
     * Devuelve el nombre del atributo trabajado en esta tabla.
     *
     * @return
     */
    public String getNombre() {
        return nombre;
    }

    /**
     * Establece el nombre del atributo que se está trabajando en esta tabla.
     *
     * @param nombre
     */
    public void setNombreSalida(String nombre) {
        this.nombreSalida = nombre;
    }

    /**
     * Devuelve el nombre del atributo trabajado en esta tabla.
     *
     * @return
     */
    public String getNombreSalida() {
        return nombreSalida;
    }

    /**
     * Devuelve el porcentaje de veracidad se este atributo si es seleccionado
     * como regla.
     *
     * @return
     */
    public float getPorcenjateVeracidad() {
        return porcentaje;
    }

    public void setPosiblesValores(ArrayList<ArrayList<String>> posiblesValores) {
        this.posiblesValores = posiblesValores;
    }

    public void setTitulos(String[] titulos) {
        this.titulos = titulos;
    }

    public TablaOneRule() {
        nombre = "Atributo";
        nombreSalida = "Salida";
        valores = new ArrayList<String>();
        valoresClase = new ArrayList<String>();
        datos = new ArrayList<ArrayList<Integer>>();
        reglas = new ArrayList<String>();
        cantidadVerdadera = 0;
        porcentaje = 0;
    }

    /**
     * Realiza los calculos correspondientes para calcular el porcentaje de
     * veracidad de este atributo.
     *
     * @param indiceColumna el indice de la columna de la vista minable con la
     * que trabajará esta tabla.
     */
    public void Determinar(int indiceColumna, int indiceClase) {

        //Primero determinamos los posibles valores que puede tomar este atributo.
        for (int i = 0; i < lista.size(); i++) {
            ArrayList<String> val = lista.get(i);
            AgregarValor(val.get(indiceColumna));
        }

        //Agrega los posibles valores de la "clase" y llena la tabla de contadores.
        for (int i = 0; i < lista.size(); i++) {
            ArrayList<String> valor = lista.get(i);
            //Obtiene el indice de fila en la tabla de contadores. Si no existen los crea.
            int iColumna = AgregarValorClase(valor.get(indiceClase));

            int iFila = BuscarValor(valor.get(indiceColumna));
            //Agrega una unidad en el campo correspondiente.
            datos.get(iFila).set(iColumna, datos.get(iFila).get(iColumna) + 1);
        }
        //Busca el valor de atributo que se repite más.
        for (int i = 0; i < datos.size(); i++) {
            int mayor = 0;
            int indice = 0;

            for (int j = 0; j < datos.get(i).size(); j++) {
                ArrayList<Integer> vals = datos.get(i);
                if (vals.get(j) > mayor) {
                    indice = j;
                    mayor = vals.get(j);
                }
            }
            //Agrega el valor de clase que se repite más como salida predeterminada.
            reglas.add(valoresClase.get(indice));
        }

        //Aqui calcula el porcentaje de veracidad para la salida predeterminada.
        for (int i = 0; i < reglas.size(); i++) {
            int ind = BuscarValorClase(reglas.get(i));
            cantidadVerdadera += datos.get(i).get(ind);
        }

        //Guarda el porcentaje de veracidad
        porcentaje = (cantidadVerdadera * 100) / lista.size();

    }

    /**
     * Busca el indice del valor en la tabla de diferentes valores.
     *
     * @param valor
     * @return
     */
    private int BuscarValor(String valor) {
        for (int i = 0; i < valores.size(); i++) {
            if (valores.get(i).equals(valor)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Agrega un nuevo valor en la lista de valores.
     *
     * @param valor
     * @return
     */
    public int AgregarValor(String valor) {
        int indice = BuscarValor(valor);
        if (indice == -1) {
            indice = valores.size();
            valores.add(valor);
            datos.add(new ArrayList<Integer>());
        }
        return indice;
    }

    /**
     * Busca el indice de un valor en la lista de valores que puede tomar la
     * "clase".
     *
     * @param valor
     * @return
     */
    private int BuscarValorClase(String valor) {
        for (int i = 0; i < valoresClase.size(); i++) {
            if (valoresClase.get(i).equals(valor)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Agrega un nuevo valor que pueda tomar la "clase".
     *
     * @param valor
     * @return
     */
    public int AgregarValorClase(String valor) {
        int indice = BuscarValorClase(valor);
        if (indice == -1) {
            indice = valoresClase.size();
            valoresClase.add(valor);
            for (int i = 0; i < datos.size(); i++) {
                datos.get(i).add(0);
            }
        }
        return indice;
    }

    /**
     * Retorna un String con la lista de reglas.
     *
     * @return
     */
    public String LeerRegla() {
       //Cuenta todos los valores de salida.
        int[] temp = new int[valoresClase.size()];
        for (int i = 0; i < reglas.size(); i++) {
            int indice = BuscarValorClase(reglas.get(i));
            temp[indice]++;
        }

        //Determina si hay un valor que se repite más que los demás.
        int mayor = -1, indice = -1;
        for (int i = 0; i < temp.length; i++) {
            if (temp[i] > mayor) {
                mayor = temp[i];
                indice = i;
            }
        }

        //Guarda el nombre del valor que se repite más.
        String pordefecto = indice > -1 ? reglas.get(indice) : "";
        String fileJava = "";
        String texto = "";
        for (int i = 0; i < valores.size(); i++) {
            //Guarda temporalmente una regla.
            String textAux = "SI " + nombre + "=" + valores.get(i) + " ==> " + nombreSalida + "=" + reglas.get(i) + "\n";
            String ifjava = "if(" + '"' + valores.get(i) + '"' + ".equalsIgnoreCase(" + nombre + ")){label.setText(" +'"'+ reglas.get(i) + '"' + ");}" + "\n";

            //Si la regla tiene como salida la definida por defecto no lo guarda.
            if (indice > -1 && reglas.get(i).equals(pordefecto)) {
                textAux = "";
                ifjava = "";
            }

            texto += textAux;
            fileJava += ifjava; 

        }

        //Si hay salida por defecto las muestra al final.
        if (indice > -1) {
            texto += "SINO " + nombreSalida + "=" + pordefecto;
            fileJava +="else{label.setText(" +'"'+ pordefecto + '"' + ");}" + "\n";
        }

        //Muestra el porcentaje de veracidad de las reglas.
        texto += "\n\nCon una veracidad del " + porcentaje + "%.";

        Plantilla.setSentencias(fileJava);
        return texto;
    }

    public String LeerReglaProlog() {

        //Cuenta todos los valores de salida.
        int[] temp = new int[valoresClase.size()];
        for (int i = 0; i < reglas.size(); i++) {
            int indice = BuscarValorClase(reglas.get(i));
            temp[indice]++;
        }

        //Determina si hay un valor que se repite más que los demás.
        int mayor = -1, indice = -1;
        for (int i = 0; i < temp.length; i++) {
            if (temp[i] > mayor) {
                mayor = temp[i];
                indice = i;
            }
        }

        //Guarda el nombre del valor que se repite más.
        String pordefecto = indice > -1 ? formatear(reglas.get(indice)) : "";




        //Campos seleccionados en la UI y su valores en la DB incluida la clase
        String camposConClase[] = formatear(titulos);
        //Valores de esos campos

        //Un nuevo vector que almacenará los campos sin la clase
        String campos[] = new String[camposConClase.length - 1];
        ArrayList<ArrayList<String>> valoresCampos = posiblesValores;

        int indiceCampo = 0;

        //Quitamos la clase de los campos
        for (int l = 0; l < camposConClase.length; l++) {

            if (!camposConClase[l].equals(formatear(nombreSalida))) {
                campos[indiceCampo++] = camposConClase[l];
            } else {
                valoresCampos.remove(l);
            }


        }

        char variables[] = new char[campos.length];

        //Sacamos la cantidad de variables necesarias del abecedario en MAYÚSCULAS
        for (int i = 65; i < 65 + campos.length; i++) {

            variables[i - 65] = (char) i;

        }

        //La variable que sirve para guardar el resultado en PROLOG (Variable de la clase)
        char variableFinal = (char) ((char) variables[variables.length - 1] + 1);


        String texto = "";

        //Declaramos las proposiciones y sus posibles valores
        for (int i = 0; i < campos.length; i++) {

            for (int j = 0; j < valoresCampos.get(i).size(); j++) {
                texto += campos[i] + "(" + valoresCampos.get(i).get(j) + ").\n";
            }

            texto += "\n";

        }

        //Declaramos la proposición de la clase
        texto += formatear(nombreSalida) + "(";




        //Letras
        for (int i = 0; i < campos.length; i++) {

            texto += variables[i] + "";

            if (i != variables.length - 1) {
                texto += ", ";
            } else {
                texto += ", " + variableFinal + ") :- ";
            }
        }


        //Declaraciones
        for (int i = 0; i < campos.length; i++) {

            texto += campos[i] + "(" + variables[i] + "), ";

        }


        //Reglas
        for (int i = 0; i < valores.size(); i++) {


            //Guarda temporalmente una regla.
            String textAux = "(" + variables[this.indice(campos, formatear(nombre))] + "='" + formatear(valores.get(i)) + "')-> " + variableFinal + "='" + formatear(reglas.get(i)) + "';";

            //Si la regla tiene como salida la definida por defecto no lo guarda.
            if (indice > -1 && formatear(reglas.get(i)).equals(pordefecto)) {
                textAux = "";
            }

            texto += textAux;


        }

        //Si hay salida por defecto las muestra al final.
        if (indice > -1) {
            texto += "" + variableFinal + "='" + pordefecto + "'.";
        }


        return texto;

    }

    //REPETIDO
    private int indice(String[] campos, String campo) {

        for (int i = 0; i < campos.length; i++) {
            if (campos[i].equals(campo)) {
                return i;
            }
        }

        return -1;

    }
    
    private String formatear(String valor){
        return formatear(new String[]{valor})[0];
    }
    
    private String[] formatear(String[] valores){
        String[] nuevo = new String[valores.length];
        for (int i = 0; i < valores.length; i++) {
            String valor = valores[i].toLowerCase();
            valor = valor.replace('ñ', 'n');
            valor = valor.replace('á', 'a');
            valor = valor.replace('é', 'e');
            valor = valor.replace('í', 'i');
            valor = valor.replace('ó', 'o');
            nuevo[i] = valor.replace('ú', 'u');
        }
        
        return nuevo;
    }
    
    
}
